local skynet = require "skynet"
local s = require "service"
local socket = require "skynet.socket"
local runconfig = require "runconfig"


conns = {} -- [fd] = conn 保存客户端连接信息
players = {} -- [playerid] = gateplayer 保存已经登录的玩家信息

-- 连接类
function conn()
    local m = {
        fd = nil,
        playerid = nil,
    }
    return m 
end 

-- 玩家类
function gateplayer()
    local m = {
        playerid = nil,
        agent = nil,
        conn = nil,
    }
    return m 
end
-- 编码
local str_pack = function(cmd, msg)
    return table.concat(msg, ",").."\r\n"
end

-- 解码
local str_unpack = function(msgstr)
    local msg = {}

    while true do
        local arg, rest = string.match( msgstr, "(.-),(.*)")
        if arg then
            msgstr = rest
            table.insert(msg, arg)
        else
            table.insert(msg, msgstr)
            break
        end
    end

    return msg[1], msg
end


local process_msg = function(fd, msgstr)
    local cmd, msg = str_unpack(msgstr)
    skynet.error("recv "..fd.." ["..cmd.."] {"..table.concat( msg, ",").."}")

    local conn = conns[fd]
    local playerid = conn.playerid
    -- 尚未完成登录流程
    if not playerid then
        local node = skynet.getenv("node")
        local nodecfg = runconfig[node]
        local loginid = math.random(1, #nodecfg.login)
        local login = "login"..loginid
            skynet.send(login, "lua", "client", fd, cmd, msg)
    -- 完成登录流程
    else
        local gplayer = players[playerid]
        local agent = gplayer.agent
            skynet.send(agent, "lua", "client", fd, cmd, msg)
    end
end 

local process_buff = function(fd, readbuff)
    while true do
        local msgstr, rest = string.match( readbuff, "(.-)\r\n(.*)")
        if msgstr then
            readbuff = rest
            process_msg(fd, msgstr)
        else
            return readbuff
        end
    end 
end 

-- 每一条连接数据处理
-- 协议格式 cmd,arg1,arg2,..
local recv_loop = function(fd)
    socket.start(fd)
    skynet.error("socket connected "..fd)
    local readbuff = ""
    while true do
        local recvstr = socket.read(fd)
        if recvstr then
            readbuff = readbuff..recvstr
            readbuff = process_buff(fd, readbuff)
        else
            skynet.error("socket close "..fd)
                disconnect(fd)
            socket.close(fd)
            return 
        end
    end 
end


-- 有新连接时
local connect = function(fd, addr)
    print("connect from "..addr.." "..fd)
        local c = conn()
    conns[fd] = c 
    c.fd = fd
    skynet.fork(recv_loop, fd)
end 

function s.init()
    local node = skynet.getenv("node")
    local nodecfg = runconfig[node]
    local port = nodecfg.gateway[s.id].port

    local listenfd = socket.listen("0.0.0.0", port)
    skynet.error("Listen socket :", "0.0.0.0", port)
    socket.start(listenfd, connect)
end

s.start(...)